// Knight.cpp
//
// Created By: Jeremy Butler
// Created On: 11-Apr-2011

#include "Knight.h"
#include "Board.h"
#include "UnitTest.h"
#include "ChessController.h"
#include <sstream>
using namespace std;

Knight::Knight() : Piece() {
  return;
}

Knight::Knight(const Color _color) : Piece(_color, KNIGHT){
  return;
}

Knight::Knight(const Knight & other) : Piece(other) {
  return;
}

Knight * Knight::Clone() const{
  return new Knight(*this);
}

Knight::~Knight(){
  return;
}

string Knight::ToString() const{
  stringstream str;

  string sColor;
  if(color == WHITE)
    sColor = "White";
  else if(color == BLACK)
    sColor = "Black";
  else
    sColor = "Colorless";

  str << sColor << " Knight";

  return str.str();
}

set<Location> Knight::GetValidMoves(const Board & board, int row, int col, bool AllMoves) const{
  set<Location> validMoves;

  GetMoves1(board, row, col, validMoves);
  GetMoves2(board, row, col, validMoves);
  GetMoves3(board, row, col, validMoves);
  GetMoves4(board, row, col, validMoves);
  GetMoves5(board, row, col, validMoves);
  GetMoves6(board, row, col, validMoves);
  GetMoves7(board, row, col, validMoves);
  GetMoves8(board, row, col, validMoves);
  
  if(!AllMoves)
    board.RemoveCheckMoves(validMoves,row,col);

  return validMoves;
}

void Knight::GetMoves1(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;

  try{
    if(board(row+2,col+1) == NULL || board(row+2,col+1)->GetColor() != GetColor()){
      location.Set(col+1,row+2);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}
void Knight::GetMoves2(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row+2,col-1) == NULL || board(row+2,col-1)->GetColor() != GetColor()){
      location.Set(col-1,row+2);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}
void Knight::GetMoves3(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row-2,col+1) == NULL || board(row-2,col+1)->GetColor() != GetColor()){
      location.Set(col+1,row-2);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}
void Knight::GetMoves4(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row-2,col-1) == NULL || board(row-2,col-1)->GetColor() != GetColor()){
      location.Set(col-1,row-2);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}

void Knight::GetMoves5(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row+1,col+2) == NULL || board(row+1,col+2)->GetColor() != GetColor()){
      location.Set(col+2,row+1);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}
void Knight::GetMoves6(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row-1,col+2) == NULL || board(row-1,col+2)->GetColor() != GetColor()){
      location.Set(col+2,row-1);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}
void Knight::GetMoves7(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row+1,col-2) == NULL || board(row+1,col-2)->GetColor() != GetColor()){
      location.Set(col-2,row+1);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}
void Knight::GetMoves8(const Board & board, int row, int col,
		       set<Location> & validMoves) const{
  Location location;
  try{
    if(board(row-1,col-2) == NULL || board(row-1,col-2)->GetColor() != GetColor()){
      location.Set(col-2,row-1);
      validMoves.insert(location);
    }
  }catch(InvalidArgumentException e){
    //cout << e.GetMessage() << endl;
  }
}

bool Knight::Test(ostream & os){
  bool success = true;

  ChessView view;
  ChessController controller(view,0);

  controller.SetView(&view);
  view.SetController(&controller);

  controller.LoadGame("games/knightTest.xml");

  set<Location> moves;

  moves = controller.model->GetValidMoves(7,0);

  TEST(moves.size() == 2);

  moves = controller.model->GetValidMoves(6,4);

  TEST(moves.size() == 0);

  moves = controller.model->GetValidMoves(3,2);

  TEST(moves.size() == 8);

  return success;
}
